package cn.jbolt.wechat.common.mp;

import cn.jbolt.core.util.JBoltRealUrlUtil;
import cn.jbolt.wechat.common.WechatApiResult;
import cn.jbolt.wechat.model.WechatReplyContent;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.WxMpMassNews;
import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage;
import me.chanjar.weixin.mp.bean.WxMpMassVideo;
import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishList;
import me.chanjar.weixin.mp.bean.material.*;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class WechatMpContext {

    public static final WxMpService SERVICE = new WxMpServiceImpl();

    public static final WxMpXmlOutMessage DEFAULT_MESSAGE = WxMpXmlOutMessage.TEXT().content("").build();

    /**
     * 添加配置
     * @param appId
     * @param config
     */
    public static void saveConfig(String appId, WxMpConfigStorage config) {
        SERVICE.addConfigStorage(appId, config);
    }


    /**
     * 移除配置
     * @param appId
     */
    public static void removeConfig(String appId) {
        SERVICE.removeConfigStorage(appId);
    }

    /**
     * 切换到指定配置的小程序
     * @param appId
     */
    public static void switchTo(String appId) {

        SERVICE.switchoverTo(appId);
    }

    /**
     * 切换结束，清空ThreadLocal的appId
     */
    public static void switchOver() {
        WxMpConfigStorageHolder.remove();
    }


    /**
     * 验证签名
     * @param timestamp
     * @param nonce
     * @param signature
     * @return
     */
    public static boolean  checkSignature(String timestamp, String nonce, String signature) {
        checkAppIdHasSet();
        boolean check = SERVICE.checkSignature(timestamp, nonce, signature);
        return check;
    }

    /**
     * 用code换取oauth2的access token.
     * @param appId
     * @param appSecret
     * @param code
     * @return
     */
    public static WechatApiResult<WxOAuth2AccessToken> getAccessToken(String appId, String appSecret, String code) {
        checkAppIdHasSet();
        try {
            WxOAuth2AccessToken accessToken = SERVICE.getOAuth2Service().getAccessToken(appId, appSecret, code);
            WechatApiResult<WxOAuth2AccessToken> result = new WechatApiResult<>();
            result.setData(accessToken);
            return result;
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("获取AccessToken失败", e);
        }
    }

    /**
     * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以.
     * @param accessToken
     * @return
     */
    public static WechatApiResult<WxOAuth2UserInfo> getAuthUserInfo(WxOAuth2AccessToken accessToken) {
        checkAppIdHasSet();
        try {
            WxOAuth2UserInfo userInfo = SERVICE.getOAuth2Service().getUserInfo(accessToken, null);
            return new WechatApiResult<>().setData(userInfo);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("获取微信用户信息失败", e);
        }
    }

    /**
     * 构造oauth2授权的url连接.
     * @param redirectUri
     * @param scope
     * @param state
     * @return
     */
    public static WechatApiResult<String> buildAuthorizationUrl(String redirectUri, String scope, String state) {
        checkAppIdHasSet();
        String url = SERVICE.getOAuth2Service().buildAuthorizationUrl(redirectUri, scope, state);
        return new WechatApiResult<>().setData(url);
    }


    /**
     * 获取关注账号列表
     * @param nextOpenId
     * @return
     */
    public static WechatApiResult<WxMpUserList> getFollowUserList(String nextOpenId) {
        checkAppIdHasSet();
        try {
            WxMpUserList wxMpUserList = SERVICE.getUserService().userList(nextOpenId);
            return new WechatApiResult<>().setData(wxMpUserList);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("获取关注列表失败", e);
        }
    }

    /**
     * 获取用户基本信息
     * @param openId
     * @return
     */
    public static WechatApiResult<WxMpUser> getBaseUserInfo(String openId) {
        checkAppIdHasSet();
        try {
            WxMpUser wxMpUser = SERVICE.getUserService().userInfo(openId);
            return new WechatApiResult<>().setData(wxMpUser);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("根据OpenId获取用户基本信息失败", e);
        }
    }

    /**
     * 上传永久素材.公众号的素材库保存总数量有上限：图文消息素材、图片素材上限为100000，其他类型为1000。
     * @param type 参考WxConsts,支持以下几个值 image video voice thumb file
     * @param file
     * @return
     */
    public static WechatApiResult<WxMpMaterialUploadResult> uploadPermanentMaterial(String type, File file) {
        checkAppIdHasSet();
        try {
            if (Objects.equals(type, WxConsts.MediaFileType.VIDEO)) {
                throw new RuntimeException("上传视频请使用WechatMpContext.uploadPermanentVideo方法");
            }
            WxMpMaterial material = new WxMpMaterial();
            material.setFile(file);
            WxMpMaterialUploadResult result = SERVICE.getMaterialService().materialFileUpload(type, material);
            return new WechatApiResult().setData(result);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("上传临时素材失败", e);
        }
    }


    /**
     * 获取图文列表
     * @param offset
     * @param count
     * @param withContent，是否带内容
     * @return
     */
    public static WechatApiResult<WxMpFreePublishList> getPublishRecords(int offset, int count, boolean withContent) {
        checkAppIdHasSet();
        try {
            WxMpFreePublishList res = SERVICE.getFreePublishService().getPublicationRecords(offset, count, withContent ? 0 : 1);
            return new WechatApiResult().setData(res);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("获取图文列表失败", e);
        }
    }

    /**
     * 获取素材列表
     * @param type
     * @param offset
     * @param count
     * @return
     */
    public static WechatApiResult<WxMpMaterialFileBatchGetResult> getMaterialRecords(String type, int offset, int count) {
        checkAppIdHasSet();
        try {
            WxMpMaterialFileBatchGetResult result = SERVICE.getMaterialService().materialFileBatchGet(type, offset, count);
            return new WechatApiResult().setData(result);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("获取素材列表失败", e);
        }
    }


    /**
     * 创建自定义菜单
     * @param json
     * @return 返回菜单id
     */
    public static WechatApiResult<String> createMenu(String json) {
        checkAppIdHasSet();
        try {
            String res = SERVICE.getMenuService().menuCreate(json);
            return new WechatApiResult().setData(res);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("创建自定义菜单失败：", e);
        }
    }

    /**
     * 上传永久素材.公众号的素材库保存总数量有上限：图文消息素材、图片素材上限为100000，其他类型为1000。
     * @param file
     * @param title 视频素材的标题
     * @param introduction 视频素材的描述
     * @return
     */
    public static WechatApiResult<WxMpMaterialUploadResult> uploadPermanentVideo(File file, String title, String introduction) {
        checkAppIdHasSet();
        try {
            WxMpMaterial material = new WxMpMaterial();
            material.setFile(file);
            material.setVideoTitle(title);
            material.setVideoIntroduction(introduction);
            WxMpMaterialUploadResult result = SERVICE.getMaterialService().materialFileUpload(WxConsts.MediaFileType.VIDEO, material);
            return new WechatApiResult().setData(result);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("上传临时素材失败", e);
        }
    }
    /**
     * 上传临时素材
     * @param type 参考WxConsts,支持以下几个值 image video voice thumb file
     * @param file
     * @return
     */
    public static WechatApiResult<WxMediaUploadResult> uploadTempMaterial(String type, File file) {
        checkAppIdHasSet();
        try {
            WxMediaUploadResult wxMediaUploadResult = SERVICE.getMaterialService().mediaUpload(type, file);
            return new WechatApiResult().setData(wxMediaUploadResult);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("上传临时素材失败", e);
        }
    }

    /**
     * 获取各类素材总数
     * @return
     */
    public static WechatApiResult<WxMpMaterialCountResult> getMaterialCount() {
        checkAppIdHasSet();
        try {
            WxMpMaterialCountResult materialCountResult = SERVICE.getMaterialService().materialCount();
            return new WechatApiResult<>().setData(materialCountResult);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("获取各类素材总数失败", e);
        }
    }


    public static WechatApiResult<WxMpMassSendResult> sendTextToUser(String openId, String text) {
        checkAppIdHasSet();
        WxMpMassOpenIdsMessage msg = new WxMpMassOpenIdsMessage();
        msg.addUser(openId);
        msg.setContent(text);
        msg.setMsgType(WxConsts.MassMsgType.TEXT);

        try {
            WxMpMassSendResult res = SERVICE.getMassMessageService().massOpenIdsMessageSend(msg);
            return new WechatApiResult<>().setData(res);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("向用户发送文字失败", e);
        }

    }


    /**
     * 发送语音给用户
     * @param openId
     * @param mediaId
     * @return
     */
    public static WechatApiResult<WxMpMassSendResult> sendVoiceToUser(String openId, String mediaId) {
        checkAppIdHasSet();
        WxMpMassOpenIdsMessage msg = new WxMpMassOpenIdsMessage();
        msg.addUser(openId);
        msg.setMsgType(WxConsts.MassMsgType.VOICE);
        msg.setMediaId(mediaId);

        try {
            WxMpMassSendResult res = SERVICE.getMassMessageService().massOpenIdsMessageSend(msg);
            return new WechatApiResult<>().setData(res);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("向用户发送语音失败", e);
        }

    }
    /**
     * 发送视频给用户
     * @param openId
     * @param mediaId
     * @return
     */
    public static WechatApiResult<WxMpMassSendResult> sendVideoToUser(String openId, String mediaId, String title, String description) {
        checkAppIdHasSet();

        WxMpMassVideo video = new WxMpMassVideo();
        video.setMediaId(mediaId);
        video.setTitle(title);
        video.setDescription(description);

        try {
            //视频需要先上传获取mediaid
            WxMpMassUploadResult res = SERVICE.getMassMessageService().massVideoUpload(video);
            WxMpMassOpenIdsMessage msg = new WxMpMassOpenIdsMessage();
            msg.addUser(openId);
            msg.setMsgType(WxConsts.MassMsgType.IMAGE);
            msg.setMediaId(res.getMediaId());

            WxMpMassSendResult res1 = SERVICE.getMassMessageService().massOpenIdsMessageSend(msg);
            return new WechatApiResult<>().setData(res1);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("向用户发送图片失败", e);
        }

    }
    /**
     * 发送图片给用户
     * @param openId
     * @param mediaId
     * @return
     */
    public static WechatApiResult<WxMpMassSendResult> sendImgToUser(String openId, String mediaId) {
        checkAppIdHasSet();
        WxMpMassOpenIdsMessage msg = new WxMpMassOpenIdsMessage();
        msg.addUser(openId);
        msg.setMsgType(WxConsts.MassMsgType.IMAGE);
        msg.setMediaId(mediaId);

        try {
            WxMpMassSendResult res = SERVICE.getMassMessageService().massOpenIdsMessageSend(msg);
            return new WechatApiResult<>().setData(res);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("向用户发送图片失败", e);
        }

    }


    /**
     * 发送文章给用户
     * @param openId
     * @param title
     * @param content
     * @param url
     * @param poster
     * @return
     */
    public static WechatApiResult<WxMpMassSendResult> sendArticleToUser(String openId, String title, String content, String url, String poster) {
        checkAppIdHasSet();

        WxMpMassNews news = new WxMpMassNews();
        WxMpNewsArticle item = new WxMpNewsArticle();
        news.addArticle(item);


        item.setTitle(title);
        item.setContent(content);
        item.setUrl(url);
        //todo 这里要处理，确认下这个地址是否有效
        item.setThumbUrl(JBoltRealUrlUtil.getWechatImage(poster, "assets/img/defaultposter.jpg"));

        try {
            //图文消息需要先上传获取mediaid
            WxMpMassUploadResult res = SERVICE.getMassMessageService().massNewsUpload(news);
            WxMpMassOpenIdsMessage msg = new WxMpMassOpenIdsMessage();
            msg.addUser(openId);
            msg.setMsgType(WxConsts.MassMsgType.IMAGE);
            msg.setMediaId(res.getMediaId());

            WxMpMassSendResult res1 = SERVICE.getMassMessageService().massOpenIdsMessageSend(msg);
            return new WechatApiResult<>().setData(res1);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return new WechatApiResult<>("向用户发送图片失败", e);
        }

    }



    private static void checkAppIdHasSet() {
        if (getCurrentAppId() == null) {
            throw new RuntimeException("未设置小程序AppId，请先调用switchTo");
        }
    }

    /**
     * 获取当前处理的appId
     * @return
     */
    public static String getCurrentAppId() {
        return WxMpConfigStorageHolder.get();
    }




}
